function WordReader:new(word_file)
    self = setmetatable({}, WordReader)
    self.word_file = word_file
    self.xml = self:to_xml()
    self.styles, self.nodes, self.texts, self.cast = {}, {}, {}, {}
    self:analyze_styles()
    self:preprocess()
    self:parse_xml()
    return self
end
function WordReader:to_xml()
    local ps_script = [[
        param (
            [string]$inputPath,
            [string]$outputPath
        )
        $PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
        $OutputEncoding = [System.Text.Encoding]::UTF8
        $word = New-Object -ComObject "Kwps.Application"
        $word.Visible = $false
        try {
            $inputPath = [System.IO.Path]::GetFullPath($inputPath)
            $outputPath = [System.IO.Path]::GetFullPath($outputPath)
            $doc = $word.Documents.Open($inputPath)
            $doc.SaveAs([ref]$outputPath, [ref]11)
        } catch {
            Write-Error "转换过程中发生错误: $_"
        } finally {
            if ($doc) {
                $doc.Close()
                [System.Runtime.Interopservices.Marshal]::ReleaseComObject($doc) | Out-Null
            }
            if ($word) {
                $word.Quit()
                [System.Runtime.Interopservices.Marshal]::ReleaseComObject($word) | Out-Null
            }
            [System.GC]::Collect()
            [System.GC]::WaitForPendingFinalizers()
        }
    ]]
    local main_path = reaper.GetResourcePath()
    local temp_xml_file = main_path .. "/transfer.xml"
    local temp_ps_file = main_path .. "/word_to_xml.ps1"
    local ps_file = io.open(temp_ps_file, "w")
    if ps_file then
        ps_file:write(ps_script)
        ps_file:close()
    end
    local cmd = string.format('powershell.exe -ExecutionPolicy Bypass -File "%s" -inputPath "%s" -outputPath "%s"',
        temp_ps_file, self.word_file, temp_xml_file)
    reaper.ExecProcess(cmd, 0)
    local xml_content = ""
    local xml_file = io.open(temp_xml_file, "r")
    if xml_file then
        xml_content = xml_file:read("*a")
        xml_file:close()
    else
        reaper.MB("无法打开文件,请联系作者", "错误", 0)
        os.remove(temp_xml_file)
        os.remove(temp_ps_file)
        return
    end
    os.remove(temp_xml_file)
    os.remove(temp_ps_file)
    return xml_content
end
function WordReader:analyze_styles()
    for style in self.xml:gmatch("<w:style(.-)</w:style>") do
        local name = style:match("w:name w:val=\"(.-)\"")
        local id = style:match("w:styleId=\"(.-)\"")
        local fill = style:match("w:fill=\"(.-)\"")
        table.insert(self.styles, { name = name, id = id, fill = fill })
    end
end
function WordReader:analyze_r_styles(wr)
    local r_styles = {}
    r_styles.r_style_id = string.match(wr, "<w:rStyle w:val=\"(.-)\"")
    r_styles.shd = string.match(wr, "<w:shd.-w:fill=\"(.-)\"")
    r_styles.has_shd = r_styles.shd ~= nil and r_styles.shd ~= ""
    r_styles.color = string.match(wr, "w:color.-w:val=\"(.-)\"")
    r_styles.has_color = r_styles.color ~= nil and r_styles.color ~= "" and r_styles.color ~= "000000"
    r_styles.has_strike = string.find(wr, "<w:strike/>") ~= nil
    return r_styles
end
function WordReader:is_title(id)
    for _, style in ipairs(self.styles) do
        if style.id == id then
            local name = style.name:lower()
            return name:match("^heading %d*$") or name == "subtitle" or name == "title"
        end
    end
    return false
end
function WordReader:has_fill(id)
    for _, style in ipairs(self.styles) do
        if style.id == id and style.fill ~= nil then
            return true
        end
    end
    return false
end
function WordReader:preprocess()
    self.xml = self.xml:gsub("<w:tbl>(.-)</w:tbl>", "")
    self.xml = self.xml:gsub("<w:instrText> DOCVARIABLE.-</w:instrText>", "")
    self.xml = self.xml:gsub("<w:instrText> PAGE.-</w:instrText>", "")
    self.xml = self.xml:gsub("<w:instrText>(.-)</w:instrText>", "<w:t>%1</w:t>")
    local patterns = { "　", " ", "  ", "   ", "    ", "%s+", "#", "§", "@", "&", "*", "∉∑" }
    self.xml = self.xml:gsub("<w:t>(.-)</w:t>", function(text)
        if text:find("^EQ") then text = "" end
        for _, pattern in ipairs(patterns) do
            text = text:gsub(pattern, ""):gsub("（", "("):gsub("）", ")"):gsub("【【", "【")
        end
        return "<w:t>" .. text .. "</w:t>"
    end)
end
function WordReader:parse_xml()
    local nodes = {}
    local function split_string(str)
        local parts = {}
        for part in string.gmatch(str, "[^%-]+") do
            table.insert(parts, part)
        end
        return parts
    end
    for wp in self.xml:gmatch("<w:p>(.-)</w:p>") do
        local has_p = wp:find("<w:pStyle ") ~= nil
        local p_id = has_p and wp:match("<w:pStyle w:val=\"(.-)\"")
        for wr in wp:gmatch("<w:r>(.-)</w:r>") do
            local rstyles = self:analyze_r_styles(wr)
            for wt in wr:gmatch("<w:t>(.-)</w:t>") do
                if wt ~= "" then
                    local style = "旁白"
                    if rstyles.has_strike then
                        style = "删除线"
                    elseif has_p and self:is_title(p_id) then
                        style = "章节"
                    elseif rstyles.has_shd or rstyles.has_color or self:has_fill(rstyles.r_style_id) then
                        local match = wt:match("【(.-)】")
                        if match and match:find("-") then
                            match = match:gsub("%b()", "")
                            local exists = false
                            for _, item in ipairs(self.cast) do
                                if item.text[2] == match then
                                    exists = true
                                    break
                                end
                            end
                            if not exists then
                                table.insert(self.cast, { text = { split_string(match), match } })
                            end
                        end
                        style = "高亮"
                    end
                    table.insert(nodes, { style = style, text = wt })
                end
            end
        end
    end
    self.nodes = nodes
    self.texts = WordReader:process_nodes(nodes)
end
function WordReader:process_nodes(nodes)
    local processed_nodes = {}
    local i = 1
    while i <= #nodes do
        local node = nodes[i]
        local style = node.style
        local text = node.text
        if text:match("^%-+$") or text:match("^《.-》$") or text == "“" or text == "”" or text == "：" or text == "有声喵youshengmiao.com" or text == "角色总表" or text == "角色列表" or text == "章节列表" or text == "角色" or text == "正文" then
            goto continue
        end
        if text == "【" or text == "(" then
            local end_char = text == "【" and "】" or ")"
            while i + 1 <= #nodes and not nodes[i + 1].text:find(end_char) do
                text = text .. nodes[i + 1].text
                i = i + 1
            end
            if i + 1 <= #nodes then
                text = text .. nodes[i + 1].text
                i = i + 1
            end
            if style == "旁白" then style = "提示" end
        end
        if style == "章节" then
            while i + 1 <= #nodes and nodes[i + 1].style == "章节" do
                text = text .. nodes[i + 1].text
                i = i + 1
            end
        end
        if style == "高亮" then
            if text:match("^【") and text:match("】$") then
                local count = 0
                for _ in text:gmatch("】【") do
                    count = count + 1
                end
                if count >= 4 then
                    goto continue
                else
                    while i + 1 <= #nodes and nodes[i + 1].style == "高亮" do
                        local next_text = nodes[i + 1].text
                        if next_text:match("^【") then
                            local match = next_text:match("【(.-)】")
                            if match and not match:find("-") then
                                text = text .. next_text
                                i = i + 1
                            else
                                break
                            end
                        else
                            text = text .. next_text
                            i = i + 1
                        end
                    end
                end
            end
        end
        if style == "高亮" and (text:match("^【(.-)】$") or text:match("^%((.-)%)$")) then
            if not text:find("-") then
                style = "提示"
            end
        end
        table.insert(processed_nodes, { style = style, text = text })
        ::continue::
        i = i + 1
    end
    return processed_nodes
end
